using System;
using System.Collections;
using System.Collections.Generic;
using System.Text;
using SpoonCore2.Client;

namespace SpoonCore2.Tools
{
	public class TimeBuffer<T> : IList<T>
	{
		private readonly int _size;
		private readonly List<BufferItem> _buffer = new List<BufferItem>();
		private readonly TimeSpan _maxAge;

		public TimeBuffer(int size, TimeSpan maxAge)
		{
			_size = size;
			_maxAge = maxAge;
		}

		public int Count
		{
			get { return _buffer.Count; }
		}

		public bool IsReadOnly
		{
			get { return false; }
		}

		public int IndexOf(T item)
		{
			int res = -1;
			int count = 0;
			foreach (BufferItem bufferItem in _buffer)
			{
				if (bufferItem.Item.Equals(item))
				{
					res = count;
					break;
				}
				count++;
			}
			return res;
		}

		public void Insert(int index, T item)
		{
			_buffer.Insert(index, new BufferItem(item));
		}

		public void RemoveAt(int index)
		{
			_buffer.RemoveAt(index);
		}

		public T this[int index]
		{
			get
			{
				_buffer[index].Access();
				return _buffer[index].Item;
			}
			set { }
		}

		private void Clean()
		{
			while (_buffer.Count > _size || (DateTime.Now - _buffer[_buffer.Count - 1].AccessTime < _maxAge))
			{
				_buffer.RemoveAt(_buffer.Count - 1);
			}
		}

		public void Add(T item)
		{
			_buffer.Add(new BufferItem(item));
			_buffer.Sort();
			Clean();
		}

		public void Clear()
		{
			_buffer.Clear();
		}

		public bool Contains(T item)
		{
			return IndexOf(item) != -1;
		}

		public void CopyTo(T[] array, int arrayIndex)
		{
			foreach (BufferItem item in _buffer)
			{
				array[arrayIndex] = item.Item;
				arrayIndex++;
			}
		}

		public bool Remove(T item)
		{
			int index = IndexOf(item);
			if (index != -1)
			{
				RemoveAt(index);
				return true;
			}
			return false;
		}

		IEnumerator<T> IEnumerable<T>.GetEnumerator()
		{
			List<T> res = new List<T>();
			foreach (BufferItem item in _buffer)
			{
				res.Add(item.Item);
			}
			return res.GetEnumerator();
		}

		public IEnumerator GetEnumerator()
		{
			return ((IEnumerable<T>)this).GetEnumerator();
		}

		private class BufferItem : IComparable<BufferItem>
		{
			private DateTime _accessTime = DateTime.Now;
			public readonly T Item;

			public BufferItem(T value)
			{
				Item = value;
			}

			public DateTime AccessTime
			{
				get { return _accessTime; }
			}

			public void Access()
			{
				_accessTime = DateTime.Now;
			}

			public int CompareTo(BufferItem other)
			{
				return _accessTime.CompareTo(other._accessTime);
			}
		}
	}
}
